 PAG
*********************************
*           SEG3
*********************************

]segnum = #$0300  ;current segment number

 ORG $E0C800  ;CODE RUNS HERE

* THIS SPACE IS SHARED WITH THE VIA AND THE RAM.

 HEX 00  ;NEED THIS BYTE SO $C7FF IS NOT REFERENCED,
    ; TO MAKE WORK IN SLOT #7

**************************************************
*  TABLE2
* Number contains processor and address mode info. Location
* in matrix is opcode.

* BITS  7  6 5  4 3 2 1 0
*       R  T T  ADDRESS MODE
*       E  Y Y  0 TO $17
*       S  P P
*       E  E E
*       R  0 0= 6502
*       V  0 1= 65C02
*       E  1 0= 65802 & 65816
*       D  1 1= RESERVED
*       0 = ALWAYS

* Address modes

* $MODE BYTES SYMBOL ADDRESS
*   0    2-3    #      IMED
*   1     3     a      ABS
*   2     4     al     ABS.L
*   3     2     d      DIR
*   4     1   i or S   ACC;IMP;STK
*   5     2   (d),y    DIR.IND.INX
*   6     2   [d],y    DIR.IND.L.INX
*   7     2   (d,x)    DIR.INX.IND
*   8     2    d,x     DIR.INX.W/X
*   9     2    d,y     DIR.INX.W/Y
*   A     3    a,x     ABS.INX.W/X
*   B     4    al,x    ABS.L.INX.W/X
*   C     3    a,y     ABS.INX.W/Y
*   D     2     r      P.C.REL
*   E     3     rl     P.C.REL.L
*   F     3    (a)     ABS.IND.
*  10     3    [a]     ABS.IND.L
*  11     2    (d)     DIR.IND.
*  12     2    [d]     DIR.IND.L
*  13     3   (a,x)    ABS.INX.IND
*  14     2    d,s     STK.REL
*  15     2   (d,s),y  STK.REL.IND.INX
*  16     2     s      STK
*  17     3    b,b     XYZ
*  18     2     #      IMED 2 bytes only (SEP,REP)
*  19     3     a      ABS program flow (JMP, JSR etc.) no effective address

* Special notes

* PER - rl ; PEI - d ; PEA - a
* REP & SEP - 2 BYTES ALWAYS
* BRK - 1 BYTES IN 6502 & C02 AND 2 BYTES IN 65816 & 802.

TABLE2 EQU *
*      LSD -->  0 1 2 3 4 5 6 7 8 9 A B C D E F

 HEX 04075654230303520400044421010142
 HEX 0D05315523080846040C2444210A0A4B
 HEX 19074254030303520400044401010142
 HEX 0D05315528080846040C24442A0A0A4B
 HEX 04074454570303520400044419010142
 HEX 0D05315557080846040C2444420A0A4B
 HEX 04074E5423030352040004440F010142
 HEX 0D05315528080846040C2444330A0A4B
 HEX 2D074E54030303520420044401010142
 HEX 0D05315508080946040C0444210A2A4B
 HEX 00070054030303520400044401010142
 HEX 0D05315508080946040C04440A0A0C4B
 HEX 00075854030303520400042401010142
 HEX 0D05315543080846040C2424500A0A4B
 HEX 00075854030303520400044401010142
 HEX 0D05315559080846040C2444530A0A4B

**************************************************
*  TABLE3
* Each 2 byte number represents the symbols displayed and the
* number of bytes for that mode.

* BIT # --> 7 6 5 4 3 2 1 0 7  6  5 4 3  2 1 0
*SYMBOL --> 0 0 # ( [ a x x 0 ,S ,X ] ) ,Y { e

* a = 1 DISPLAY BYTES AS IS
* a = 0 DISPLAY RELATIVE ADDRESS

* xx = NUMBER OF BYTES IN INSTRUCTION - 1
* 00 = 1, 01 = 2, 10 = 3, 11 = 4

* { = 0 NO ADDRESS DISPLAYED
* { = 1 DISPLAY ADDRESS

* e = 0 RELATIVE OFFSET OR NO ADDRESS
* e = 1 EFFECTIVE ADDRESS

TABLE3 EQU *
* Start with mode 0

 DDB %0010010100000000 ; mode $0 #nn or #nnnn
 DDB %0000011000000011 ; mode $1  a
 DDB %0000011100000011 ; mode $2  al
 DDB %0000010100000011 ; mode $3  d
 DDB %0000010000000000 ; mode $4  i or S
 DDB %0001010100001111 ; mode $5  (d),y
 DDB %0000110100010111 ; mode $6  [d],y
 DDB %0001010100101011 ; mode $7  (d,x)
 DDB %0000010100100011 ; mode $8  d,x
 DDB %0000010100000111 ; mode $9  d,y
 DDB %0000011000100011 ; mode $A  a,x
 DDB %0000011100100011 ; mode $B  al,x
 DDB %0000011000000111 ; mode $C  a,y
 DDB %0000000100000010 ; mode $D  r
 DDB %0000001000000010 ; mode $E  rl
 DDB %0001011000001011 ; mode $F (a)
 DDB %0000111000010011 ; mode $10 [a]
 DDB %0001010100001011 ; mode $11 (d)
 DDB %0000110100010011 ; mode $12 [d]
 DDB %0001011000101011 ; mode $13 (a,x)
 DDB %0000010101000011 ; mode $14 d,s
 DDB %0001010101001111 ; mode $15 (d,s),y
 DDB %0000010100000000 ; mode $16 s
 DDB %0000011000000000 ; mode $17 b,b
 DDB %0010010100000000 ; mode $18 #nn (SEP,REP)
 DDB %0000011000000000 ; mode $19 a (JMP,JSR,PEA)
TBL3END

**************************************************
* Mnemonic table
* Contains mnemonics compressed into 2 bytes.

MNEMTABL

*ADC
 HEX 0483
*AND
 HEX 05C4
*ASL
 HEX 066C
*BCC
 HEX 0863
*BCS
 HEX 0873
*BEQ
 HEX 08B1
*BIT
 HEX 0934
*BMI
 HEX 09A9
*BNE
 HEX 09C5
*BPL
 HEX 0A0C
*BRA
 HEX 0A41
*BRK
 HEX 0A4B
*BRL
 HEX 0A4C
*BVC
 HEX 0AC3
*BVS
 HEX 0AD3
*CLC
 HEX 0D83
*CLD
 HEX 0D84
*CLI
 HEX 0D89
*CLV
 HEX 0D96
*CMP
 HEX 0DB0
*COP
 HEX 0DF0
*CPX
 HEX 0E18
*CPY
 HEX 0E19
*DEC
 HEX 10A3
*DEX
 HEX 10B8
*DEY
 HEX 10B9
*EOR
 HEX 15F2
*INC
 HEX 25C3
*INX
 HEX 25D8
*INY
 HEX 25D9
*JML
 HEX 29AC
*JMP
 HEX 29B0
*JSL
 HEX 2A6C
*JSR
 HEX 2A72
*LDA
 HEX 3081
*LDX
 HEX 3098
*LDY
 HEX 3099
*LSR
 HEX 3272
*MVN
 HEX 36CE
*MVP
 HEX 36D0
*NOP
 HEX 39F0
*ORA
 HEX 3E41
*PEA
 HEX 40A1
*PEI
 HEX 40A9
*PER
 HEX 40B2
*PHA
 HEX 4101
*PHB
 HEX 4102
*PHD
 HEX 4104
*PHK
 HEX 410B
*PHP
 HEX 4110
*PHX
 HEX 4118
*PHY
 HEX 4119
*PLA
 HEX 4181
*PLB
 HEX 4182
*PLD
 HEX 4184
*PLP
 HEX 4190
*PLX
 HEX 4198
*PLY
 HEX 4199
*REP
 HEX 48B0
*ROL
 HEX 49EC
*ROR
 HEX 49F2
*RTI
 HEX 4A89
*RTL
 HEX 4A8C
*RTS
 HEX 4A93
*SBC
 HEX 4C43
*SEC
 HEX 4CA3
*SED
 HEX 4CA4
*SEI
 HEX 4CA9
*SEP
 HEX 4CB0
*STA
 HEX 4E81
*STP
 HEX 4E90
*STX
 HEX 4E98
*STY
 HEX 4E99
*STZ
 HEX 4E9A
*TAX
 HEX 5038
*TAY
 HEX 5039
*TCD
 HEX 5064
*TCS
 HEX 5073
*TDC
 HEX 5083
*TRB
 HEX 5242
*TSB
 HEX 5262
*TSC
 HEX 5263
*TSX
 HEX 5278
*TXA
 HEX 5301
*TXS
 HEX 5313
*TXY
 HEX 5319
*TYA
 HEX 5321
*TYX
 HEX 5338
*WAI
 HEX 5C29
*WDM
 HEX 5C8D
*XBA
 HEX 6041
*XCE
 HEX 6065

* ASSEMBLER DIRECTIVES

*HEX
 HEX 20B8

*ADR
 HEX 0492

****************************************
* THIS POINT MUST BE $CA00 OR ABOVE.
****************************************

 ERR *-1/$E0CA00
 DS $E0CA00-*,$FF

***** TABLE4 *****
* POSSIBLE SYMBOLS USED IN OPERAND

 HEX 00  ;SO DOESN'T LOOK LIKE 2 BYTE SYMBOL
TABLE4
 ASC "#",00
 ASC "(",00
 ASC "[",00
 ASC ",S",00
 ASC ",X",00
 ASC "]",00
 ASC ")",00
 ASC ",Y",00

********************************
*  MINI ASSEMBLER
********************************

COMDMA EQU *
 BEQ MANOADDR ;IF NO ADDRESS FOLLOWS
 JSR LOADMEM  ;GET ADDRESS
 BCC MANOADDR ;ADDRESS OK
BPERR3 LDA #BADPAR  ;BAD PARAMETER ERROR NUMBER
ERREXIT3
 JSR TRANSFR3 ;INVALID ADDRESS
 DFB ERRBEEPC ;CODE
 JMP GETCOM3

MANOADDR
 JSR DISASM  ; DISPLAY INSTRUCTION
 LDX #19  ;SPACES
 JSR TRANSFR3
 DFB PRBL2C  ;CODE
 LDA #"!"
 STA PROMPT  ;NEW PROMPT
 JSR TRANSFR3 ;GET INPUT LINE
 DFB GETLNC  ;CODE
 BCC :NOESC
 JMP GETCOM3  ;if "esc" key
:NOESC INX   ;X=0 IF ONLY <CR> ENTERED
 LDY #00
 JSR TRANSFR3 ;GET FIRST CHARACTER
 DFB GETCHRC  ;CODE
 BNE MASTLET1 ;CHECK INPUT

* Only CR entered so go to next instruction
* NUMDISP = # of bytes in instruction-1

 LDY NUMDISP
MAINCMEM
 JSR INCMEMLH ;INC MEM POINTER
 DEY
 BPL MAINCMEM
 BMI MANOADDR ;GO TO NEXT INSTRUCTION

MASTLET1
 STA MNEMCOMP ;TEMP SAVE

* Cause error if a soft break is at this location

 STY TEMP+1  ;SAVE Y
* LETTER 1,2,3 USED BY VALIDAD
 MEMORY16
 LDA MEMLOW
 STA LETTER1  ;used by VALIDAD
 MEMORY8
 JSR TRANSFR3 ;IS THIS LOCATION A REAL BREAK?
 DFB VALIDADC ;CODE
 BNE :OK  ;IF NO
 JMP MANOTRAM ;IF REAL BRK, DISPLAY **ACCESS ERROR**
:OK LDY TEMP+1  ;RESTORE Y

 LDA MNEMCOMP ;RESTORE
 ASL MNEMCOMP+1 ;MAKE BIT 0 = 0
 JSR PACKMNEM ;PACK 1ST LETTER OF MNEMONIC
 JSR TRANSFR3 ;
 DFB GETCHRC  ;CODE
 BEQ MAERR
 JSR PACKMNEM ;PACK 2ND LETTER
 JSR TRANSFR3 ;
 DFB GETCHRC  ;CODE
 BEQ MAERR
 JSR PACKMNEM ;PACK 3RD LETTER
 STX XBUFF

* MNEMCOMP & MNEMCOMP+1 contain 2 byte mnemonic in compressed form.
* Compare with compressed mnemonics in MNEMTABL

 LDX #0
FINDMNEM
 MEMORY16
 LDA MNEMCOMP
 CMP $C800  ;SELECT EXT ROM
 CMP MNEMTABL,X ;DO THEY MATCH?
 MEMORY8
 STA $CF00  ;ENABLE EXT RAM
 BNE NEXTMNEM ;IF NO, TRY NEXT MNEM
 BEQ FOUNDMNE ;IF YES

NEXTMNEM
 INX
 INX
 CPX #$BC  ;OUT OF MNEMONICS?
 BLT FINDMNEM ;IF NO

* If out of mnemonics or other error, come here.

MAERROP LDY #10  ;OPCODE ERROR
MAERR TYA
 CLC
 ADC #11  ;POSITION UNDER ERROR
 TAX
 JSR TRANSFR3 ;PRINT SPACES (X REG)
 DFB PRBL2C  ;CODE
 LDA #"^"
 JSR COUT3  ;INDICATE WHERE ERROR WAS
 JSR TRANSFR3 ;PRINT "ERR" RING BELL
 DFB PRERRC  ;code
 JSR TRANSFR3 ;<RETURN>
 DFB CROUTC  ;code
 JMP MANOADDR ;TRY AGAIN

* Found the mnemonic in MNEMTABL

FOUNDMNE STX OPCODE  ;USE OPCODE AS TEMP STORAGE FOR # OF MNEMONIC

* Build a 2 byte number of display info, as in TABLE 3

 STZ MODE  ;TEMP BUFFER
 STZ OPERAND
 LDA #02  ;SET BIT USED AS FINISHED FLAG
 STA OPERAND+1 ;FORM 2 BYTES HERE
CHEKSYMB
 LDX XBUFF  ;GET STRING POINTER
FROMADRS
 JSR TRANSFR3 ;GET CHAR
 DFB GETCHRC  ;CODE
 STX XBUFF
 LDX MODE  ;TABLE4 POINTER
 CMP TABLE4,X
 BEQ ISSYMB

* Symbols don"t match

 DEY
 INC XBUFF  ;TRY SAME CHAR AGAIN
 LDA TABLE4-1,X ;WAS IT A 2 BYTE SYMBOL
 BEQ CLRSHFT  ;IF NO
 DEY   ;IF YES, BACKUP TO 1ST CHARACTER
 INC XBUFF
CLRSHFT CLC
 BCC SHFTSYMB ;<ALWAYS>

* Symbols do match

ISSYMB LDA TABLE4+1,X ;IS IT TWO BYTE SYMBOL?
 BNE INCSYMB  ;IF YES, BOTH BYTES MUST MATCH
 SEC
SHFTSYMB ROL OPERAND+1
 ROL OPERAND
 BMI SYMBDONE ;FLAG BIT IS IN BIT7

 CPX #19  ;OUT OF SYMBOLS TO CHECK?
 BGE CLRSHFT  ;IF YES, KEEP SHIFTING TILL DONE

* Inc TABLE4 pointer to next symbol

 INX
 INX
 LDA TABLE4,X
 BNE NEXTSYM
INCSYMB INX
NEXTSYM
 STX MODE

* Is address next ?

 CPX #$6  ;CHECK FOR ADDRESS?
 BNE CHEKSYMB

* Is address
* Check for hex data & read

 LDX XBUFF  ;GET STRING POINTER

 LDA MEMPBR
 PHA   ;PREVENT CHKREADA FROM CHANGING MEMPBR
 JSR TRANSFR3 ;READ NUMBER, START AT CURRENT CHAR
 DFB CHKREADAC ;code
 PLA
 STA MEMPBR  ;RESTORE

 INC INLENGTH
 LSR INLENGTH ;CONVERT TO # OF BYTES IN ADDRESS
 LDA OPERAND+1
 SEC
 ROL   ;ALWAYS SET BIT2 OF 1ST BYTE
 ASL
 ASL
 ORA INLENGTH ;BIT 7 OF BYTE 2 IS ALWAYS 0
 ASL
 STA OPERAND+1 ;INCLUDE # OF BYTES INFO
 ROL OPERAND
 DEY
 INX
 JMP FROMADRS

* Assembler input error

TOMAERR JMP MAERR

* The two bytes representing the mode of the instruction
* are finished. Find the possible modes of the instruction.
* The relative instructions; BEQ $34, may look like mode #3
* BEQ $0034 will look like mode #1. Mode #E will look like
* mode #2, some modes look the same. Try for exact match,
* if mode of MNEM & this mode don't match try to match in
* TABLE3 with different mode(some look the same).
* If still no match with MNEM, or in TABLE3, then maybee is
* relative instruction. Set bit 2 of 1st byte to 0 and try
* for match, if no match, decrease # of bytes (bits 0 & 1)
* by 1 and try again.

* Find the opcode of the instruction by matching the
* mode of the input OPERAND with the mode of the input MNEM.

SYMBDONE
 LDX #8  ;SET UP FOR DISPLAYING GENERATED CODE
 JSR SPACES  ;ALIGN WITH PREVIOUS CODE

:LOOKOP JSR FINDOPCD ;LOOK FOR OPCODE
 BCC FOUNDOP  ;OPCODE IN OPCODE BUFFER, MODE IN MODE

* No match found between MNEM modes & OPERAND mode
* If mode is # word then force OPERAND to 1 byte mode & try again

 LDA OPERAND
 CMP #%10100110 ;is it # WORD
 BNE :TRYREL  ;if no
 LDA #%00100101 ;force to # BYTE
 STA OPERAND
 BRA :LOOKOP  ;try again

* No match found between MNEM modes & OPERAND mode
* try looking at relative modes with Z page destinations
* or relative long.

:TRYREL AND #%00111011 ;SET BITS 7, 6, & 2 TO 0
 STA OPERAND
 JSR FINDOPCD ;LOOK FOR OPCODE
 BCC RELATIVE ;FOUND IT. RELATIVE INST.

* No match try looking at all other relative modes

 LDA #%00111100
 BIT OPERAND
 BNE LOOKDIR  ;NOT RELATIVE MODE SO LOOK FOR DIRECTIVE
 DEC OPERAND  ;REDUCE # OF BYTES BY 1 TO MATCH RELATIVE
 JSR FINDOPCD
 BCC RELATIVE ;FOUND IT RELATIVE INST.

*-----------------------------------------------
* Not able to match MNEM modes with operand mode
* so look for assembler directive

LOOKDIR LDX OPCODE  ;GET MNEMONIC NUMBER
 CPX #$B8  ;IS IT HEX?
 BNE :CKADR  ;IF NO
 LDA #1  ;1 BYTE OF HEX DATA
 BNE ADRHEX
:CKADR CPX #$BA  ;IS IT ADR?
 BNE TOMAERR  ;IF NOT MUST BE MA ERROR
 LDA #2  ;2 BYTES OF ADR DATA
 BNE ADRHEX  ;<ALWAYS>

*----------------------------------
***** RELATIVE MODE *****

RELATIVE
 JSR INCMEMLH ;CONVERT ADDRESS TO RELATIVE OFFSET
 JSR INCMEMLH

* Offset is calculated from address of instruction
* following the branch operand
* subtract MEMLOW & MEMHI from TEMP+1 & TEMP+2, which should
* give me the branch offset

 LDA MODE  ;IS IT REL. LONG
 CMP #$E*2  ;MODE IS TIMES 2
 CLC
 BEQ RELLONG  ;IF YES, SUBTRACT AN EXTRA 1
 SEC
RELLONG LDA LETTER1  ;LOW BYTE OF OPERAND ADDRESS
 SBC MEMLOW
 STA LETTER1
 LDA LETTER2  ;HI BYTE OF OPERAND
 SBC MEMHI
 STA LETTER2
 BNE BNCHBACK ;IF NOT 0 MUST BE BRANCHING BACKWARD
 BIT LETTER1  ;IF FORWARD BRANCH LOW BYTE CAN'T BE NEGATIVE
 BMI BRNCHOUT ;IF IT IS THEN BRANCH IS OUT OF RANGE
 BPL OFFSETOK ;IF OK
BNCHBACK
 CMP #$FF
 BNE BRNCHOUT ;THE MSBYTE MUST BE $00 OR $FF
 BIT LETTER1  ;IF BRANCHING BACKWARD BYTE CAN'T BE POSITIVE
 BPL BRNCHOUT
OFFSETOK
 JSR DECMEMLH ;DEC MEMLOW & MEMHI
 JSR DECMEMLH

* Put the instruction into RAM
* Found the proper opcode

FOUNDOP LDA OPCODE
 JSR INITMMV  ;INIT LOWADD W/MEMLOW, STA, LDA, VERIFY
 BNE MANOTRAM ;STORE, Z BIT SET IF VERIFY OK
 JSR BYTESP3  ;DISPLAY CODE BYTE & SPACE
 JSR INCMEMLH ;INC MEMLOW & MEMHI POINTERS

 LDX MODE  ;MODE IS TIMES 2
 BEQ STOROPER ;If # mode then use current INLENGTH

 CMP $C800  ;DISABLE EXT RAM
 LDA TABLE3,X
 CMP $CF00  ;ENABLE EXT RAM
 AND #$03  ;# OF BYTES IN OPERAND

* Enter here if assembler directive
ADRHEX STA INLENGTH ;USED BY STOROPER
 BEQ MANEXT  ;MUST BE IMPLIED
 LDX #0

* Store INLENGTH number of bytes
STOROPER LDA LETTER1,X
 JSR INITMMV
 BNE MAERRBY2 ;LOCATION NOT RAM
 JSR BYTESP3  ;DISPLAY ACC & SPACE
 JSR INCMEMLH
 INX
 CPX INLENGTH
 BLT STOROPER

* Disassemble the next instruction

MANEXT JSR TRANSFR3 ;CARRIAGE RETURN
 DFB CROUTC  ;code
 JMP MANOADDR

MAERRBY3 JSR DECMEMLH ;DEC MEMLOW & MEMHI
MAERRBY2 JSR DECMEMLH
MANOTRAM JSR TRANSFR3 ;DISPLAY "**ACCESS ERROR**"
 DFB DISNOTRMC ;CODE
 JMP MANEXT

BRNCHOUT LDA MODE  ;IF REL LONG
 CMP #$E*2  ;MODE IS TIMES 2
 BEQ OFFSETOK
 JSR TRANSFR3 ;DISPLAY "BRANCH OUT OF RANGE"
 DFB DISBROUTC ;CODE
 JSR DECMEMLH
 JSR DECMEMLH
 JMP MANEXT

*****************************************
*   DISASM
* Disassemble the current instruction.
* MEMLOW & MEMHI contain the program counter lo & hi bytes
* MEMPBR contains the program bank register.
*****************************************

* Use current MEMPBR

DISASM JSR TRANSFR3 ;MEM DISPLAY
 DFB DSMEMCOLC ;code
 LDX #0
 LDY #0
 JSR GETBYTE  ;GET OPCODE
 STA OPCODE
 TAY   ;USED AS POINTER FOR TABLE3
 CMP $C800  ;DISABLE EXT RAM
 LDA TABLE2,Y ;INSTRUCTIONS ADDRESS MODE & PC TYPE
 CMP $CF00  ;ENABLE EXT RAM
 AND #$60  ;ISOLATE PC TYPE
 BEQ TYPEOK  ;IF 6502 MUST BE OK
 CMP #$20  ;IS IT 65C02 INSTRUCTION?
 BNE CHK816  ;IF NO, MUST BE 816
 LDA CMOSFLAG ;IS THE 65C02 ALLOWED?
 BNE TYPEOK  ;IF NOT RESTRICTED TO 65C02, IT IS OK
 JMP MAKENOP  ;INVALID INSTRUCTION ???
CHK816 BIT CMOSFLAG ;IS 65816 ALLOWED?
 BVS TYPEOK  ;IF YES
 JMP MAKENOP  ;INVALID INSTRUCTION ???

TYPEOK CMP $C800  ;DISABLE EXT RAM
 LDA TABLE2,Y ;GET ADD. MODE & VALID PC INFO
 CMP $CF00  ;ENABLE EXT RAM
 AND #$1F  ;LEAVE ONLY ADD. MODE INFO
 ASL   ; TIME 2
 TAY   ;ADDRESS MODE TIMES 2 (OFFSET TO TABLE3)
 STA MODE
 CMP $C800  ;DISABLE EXT RAM
 LDA TABLE3,Y ;GET # OF BYTES & DISPLAY INFO
 CMP $CF00  ;ENABLE EXT RAM
 AND #$03  ;GET # OF BYTES IN INSTRUCTION
 TAX
 TYA   ;TEST FOR # MODE Y=0?
 BNE SVNUMBYT ;IF NOT
*8 OR 16 BIT
 BIT EMULATE  ;IS 816 MODE ON
 BMI SVNUMBYT ;IF NO THEN 8 BIT
 LDA OPCODE
 AND #$0F
 CMP #$09  ;IS OPCODE ACCUMULATOR INSTRUCTION
 BNE CHK16X  ;IF NO, CHECK FOR 16 BIT INDEX
* Check for 16 bit data
 LDA #$20
 BIT STATUS  ;= 0 IF 16 BIT DATA
 BNE SVNUMBYT ;IF 8 BIT
 BEQ SIXTEEN  ;IF 16 BIT
CHK16X LDA #$10
 BIT STATUS  ;= 0 IF 16 BIT INDEX
 BNE SVNUMBYT ;IF 8 BIT
SIXTEEN INX   ;16 BIT DATA SO DISPLAY 3 BYTES

SVNUMBYT
 STX NUMDISP  ;# OF BYTES TO DISPLAY-1
 LDY #0  ;SET FOR GETBYTE
 STY MLIFLAG  ;0=MLI CALL, MAKE <> 0 IF NOT MLI
 STY P16FLAG ;0=P16 call, make <> 0 if not
 JSR DISPBYTS ;DISPLAY THE HEX FORM OF INSTRUCTION

* Print mnemonic

 LDX OPCODE

* Get offset that points to compressed mnemonic
 JSR TRANSFR3 ;LDA TABLE1,X
 DFB LTABLE1C ;CODE
 TAX
 CMP $C800
 MEMORY16
 LDA MNEMTABL,X ;Get compressed MNEM
 CMP $CF00
 STA MNEMCOMP
 MEMORY8

* Unpack the 2 byte mnemonic & display

 LDX #3
UNPACK LDA MNEMCOMP
 LSR
 LSR
 AND #%00011111 ;LETTER
 CLC
 ADC #$C0
 JSR COUT3  ;
 JSR LEFT5 ;SHIFT MNEMCOMP LEFT 5 TIMES
 DEX
 BNE UNPACK

 LDA #$A0
 JSR COUT3  ;SPACE

* Display the rest of the instruction
 LDY MODE  ;GET OFFSET TO TABLE3
 CMP $C800  ;DISABLE EXT RAM
 LDA TABLE3+1,Y ;get the 2nd byte of display info
 STA TEMP+2  ;save for later
 LDA TABLE3,Y ;GET THE 1ST BYTE OF DISPLAY INFO
 CMP $CF00  ;ENABLE EXT RAM
 ASL
 ASL
 LDX #0
NEXTSYMB
 ASL
 PHA   ;SAVE
 BCC NOSYMBOL
GETSYMB
 LDA TABLE4,X ;GET THE SYMBOL
 BEQ SYMBEND  ;0=STOP
 JSR COUT3  ;DISPLAY SYMBOL
 INX
 BNE GETSYMB
NOSYMBOL
 INX
 LDA TABLE4,X
 BNE NOSYMBOL
SYMBEND INX
 PLA
 CPX #6  ;DISPLAY ADDRESS?
 BNE :NO ;IF NO
 JMP DISPADDR ;YES
:NO CPX #19  ;DISPLAY EFFECTIVE ADD.?
 BLT NEXTSYMB ;IF NO
 ASL   ;DISPLAY EFFECTIVE ADD?
 BCC :CHKMLI  ;IF NO
 PHA
 LDA #$A0
 JSR COUT3  ;
 LDA #"{"
 JSR COUT3  ;
 PLA
 ASL   ;EFFECTIVE ADDRESS?
 BCC RELADDRS ;IF NO
 JSR TRANSFR3 ;CALC EFFECTIVE ADDRESS
 DFB CALCEFFC ;code

* Display effective address
 LDA EFFADRS+2
 JSR TRANSFR3
 DFB PRBYTEC  ;code
 LDA EFFADRS+1
 LDX EFFADRS
 JSR TRANSFR3
 DFB PRNTAXC  ;code

*------------------
* Check for MLI call

:CHKMLI LDA P16FLAG ;was this a P16 call?
 BEQ :DOP16 ;if yes
:CKMLI LDA MLIFLAG  ;WAS THIS AN MLI CALL ?
 BNE :ENDDIS  ;IF NO
:DOP16 JSR TRANSFR3 ;DO <CR>
 DFB CROUTC  ;code
 LDX #8
 JSR SPACES  ;8 SPACES
 LDX #2  ;# OF BYTES-1, preset for MLI
 LDY #3 ;point at MLI stuff
 LDA P16FLAG ;was this a P16 call?
 BNE :CONTMLI ;if no
 INX
 INX
 INX  ;set for 6 bytes of P16 stuff
 INY  ;point at P16 stuff
:CONTMLI JSR DISPBYTS ;DISPLAY THE MLI or P16 PARAMETER DATA
* STZ MLIFLAG ;CLEAR flag
* LDX #4
* JSR SPACES  ;4 SPACES, RETURNS WITH X=0
* LDY #3
* JSR GETBYTE
* JSR TRANSFR3 ;PRINT MLI CODE BYTE
* DFB PRBYTEC
* LDA #$A0
* JSR COUT3  ;SPACE
* INY
* JSR GETBYTE
* TAX
* INY
* JSR GETBYTE
* JSR TRANSFR3 ;PRINT MLI ADDRESS
* DFB PRNTAXC
 LDX NUMDISP
 INX
 INX   ;INC NUMDISP TO REFLECT
 INX   ;3 XTRA BYTES OF MLI
 STX NUMDISP
:ENDDIS JMP ENDDISAS

* Not effective address so indicate relative offset

RELADDRS LDA #0
 STA TEMP+1
 LDY NUMDISP  ;# BYTES IN INSTRUCTION-1
 JSR GETBYTE  ;LOAD HI ORDER BYTE OF OFFSET. OP LO HI
 STA TEMP
 DEY
 BEQ :ONEBYT
 JSR GETBYTE  ;GET LO BYTE OF OFFSET
 STA TEMP+1
:ONEBYT LDA TEMP  ;GET HI BYTE OR ONLY BYTE
 BPL :POSOFF  ;POSITIVE OFFSET

* Take 2'S compliment of neg offset
 LDA #0
 SEC
 SBC TEMP+1  ;TEMP+1 is 0 for 1 byte offset and
 STA TEMP+1  ; will not affect the carry flag
 LDA #0
 SBC TEMP
 STA TEMP  ;2'S COMP. FINISHED
 LDA #"-"
 BNE :SIGN

:POSOFF LDA #"+"
:SIGN JSR COUT3  ;DISPLAY SIGN OF OFFSET
 LDA TEMP
 JSR TRANSFR3 ;PRINT ACC AS 2 HEX DIGITS
 DFB PRBYTEC  ;CODE
 TYA   ;TEST Y
 BEQ :OFFEND  ;ONE BYTE OFFSET
 LDA TEMP+1  ;LOW BYTE OF OFFSET
 JSR TRANSFR3 ;DISPLAY AS 2 HEX DIGITS
 DFB PRBYTEC  ;CODE
:OFFEND LDA #"}"
 JSR COUT3  ;
 JMP ENDDISAS ;END OF DISASSEMBLY


* Display the address bytes of the instruction (E.G. LDA #$XX)

DISPADDR ASL   ;TEST BIT 2 FROM TABLE 3 (RELATIVE ADDR.?)
 BCS DISPASIS ;DISPLAY ADDRESS AS IS

*-------------------------------------------------
* Calculate relative address
* Our PCHI & PCLO is pointing at the current instruciton, but a branch
* offset works off the following instructions PC. So add the number of
* bytes in the branch instruction, (2 or 3), to the offset

 STZ TEMP+1  ;HI BYTE
 LDY NUMDISP  ;# BYTES IN INSTRUCTION-1

* Get 1 byte offset or hi byte of 2 byte offset
 JSR GETBYTE
 CPY #2
 BEQ TWOBYTE
 STA TEMP  ;ONLY USED FOR 8 BIT OFFSET
 ORA #00  ;SET FLAGS
 BPL NOEXTEND ;IF POS # DO NOT SIGN EXTEND
 LDA #$FF
TWOBYTE STA TEMP+1  ;SIGN EXTEND 8 BIT NEG OFFSET, OR HI BYTE
NOEXTEND DEY  ;DEC. INSTRUCTION POINTER
 BEQ ONEOFFST ;IF NOT BYTE OFFSET
 JSR GETBYTE
 STA TEMP

* Add the number of bytes in the branch instruction
* to the offset. Add offset to PC & display address

ONEOFFST SEC   ;ADD IN CARRY BECAUSE NUMDISP IS 1 LESS
 LDA TEMP  ;THAN # OF BYTES
 ADC NUMDISP
 PHP   ;SAVE CARRY
 CLC
 ADC MEMLOW  ;ADD TO PC
 TAX
 LDA MEMHI
 ADC #0  ;ADD IN CARRY FROM MEMLOW IF ANY
 PLP   ;GET CARRY FROM NUMDISP IF ANY
 ADC TEMP+1  ;ADD IN HI BYTE OFFSET
 JSR TRANSFR3 ;DISPLAY ADDRESS
 DFB PRNTAXC  ;CODE
 JMP T3BYTE2  ;GET BYTE2 FROM TABLE3

* Display the address bytes as is

DISPASIS LDY NUMDISP  ;# BYTES IN INSTRUCTION-1
 BEQ T3BYTE2  ;ONLY 1 BYTE INSTRUCTION

 LDA TEMP+2  ;get TABLE3 2nd byte
 ROR
 ROR   ;bit7 = 0 = no effective address or relative
 PHA   ;save effective address flag
 BPL DISPAS2  ;don't clear effective address

* Clear EFFADRS
 LDX #2
:NEXT STZ EFFADRS,X
 DEX
 BNE :NEXT

 LDY NUMDISP
DISPAS2 JSR GETBYTE  ;GET THE HIGHEST ORDER ADDRESS BYTE
 PLX   ;get effective address flag
 PHX
 BPL :NOEFF  ;if no effective address or relative
 STA EFFADRS-1,Y ;SAVE FOR EFFECTIVE ADDRS.
:NOEFF JSR TRANSFR3 ;PRINT THE BYTE
 DFB PRBYTEC  ;CODE
 DEY
 BNE DISPAS2  ;NEXT BYTE
 PLX   ;restore stack

* retrieve 2nd byte of TABLE3 display info

T3BYTE2 LDA TEMP+2  ;get 2nd byte of display info
 ASL   ;BIT 7 EMPTY
 LDX #6  ;RESET X
 JMP NEXTSYMB ;CONTINUE DISPLAYING INSTRUCTION

* Display "???"

MAKENOP TYA   ;OPCODE
 JSR TRANSFR3 ;DISPLAY OPCODE
 DFB PRBYTEC  ;code
 LDX #10
 JSR TRANSFR3 ;LINE UP
 DFB PRBL2C  ;code
 LDX #3
PRINT? LDA #"?"
 JSR COUT3  ;
 DEX
 BNE PRINT?
 STX NUMDISP  ;# OF BYTES - 1

*---------------------------------
*  End disassemble routine
*---------------------------------

ENDDISAS
 JSR TRANSFR3 ;RETURN
 DFB CROUTC  ;code
 RTS   ;END OF DISASSEMBLY

**************************************************
* SUBROUTINES
**************************************************

*-----------------------------------
* Display the hex form of the instruction.
* Set MLIFLAG to non 0 if not JSR $BF00
* Enter with X=number of bytes-1
*
* Spaces entry point displays X number of spaces.
*-----------------------------------

* MLI code for comparison
MLICODE JSR $BF00
P16CODE JSL $E100A8

DISPBYTS JSR GETBYTE
 CMP MLICODE,Y ;DOES IT MATCH MLI CALL?
 BEQ :MAYBE ;THIS PART MATCHES
 INC MLIFLAG  ;NOT AN MLI CALL
:MAYBE CMP P16CODE,Y ;does it match P16 call?
 BEQ :MAYBE16 ;this part matches
 INC P16FLAG ;not a P16 call
:MAYBE16 JSR BYTESP3  ;PRINT ACC AS HEX BYTE & SPACE
 INY
 DEX
 BPL DISPBYTS
 LDX NUMDISP  ;# OF BYTES DISPLAYED-1
 INX

* Print proper number of spaces so all mnemonics line up
 LDA #12
:LOOP SEC
 SBC #3
 BEQ DBYTEEND ;NO SPACES
 DEX
 BNE :LOOP
 TAX   ;# OF SPACES TO PRINT

*-------------------------------
* Alternate entry point

SPACES JSR TRANSFR3 ;PRINT X NUMBER OF SPACES
 DFB PRBL2C  ;CODE
DBYTEEND
 RTS

*--------------------------------
* Print the ACC as 1 hex byte followed by 1 space

BYTESP3 JSR TRANSFR3 ;
 DFB PRBYTEC  ;CODE
 LDA #$A0  ;SPACE

*-----------------------------

COUT3 JSR TRANSFR3
 DFB COUTC
 RTS

*------------------------------
* Decrement MEMLOW by 1

DECMEMLH MEMORY16
 DEC MEMLOW
 MEMORY8
 RTS

* FINDOPCD subroutine
* Compare the operand of the input instruction with the operand of each
* mode in TABLE 3. If a match is found then check TABLE 2 to see if
* the mnemonic is available in that mode. If it is then save mode in
* MODE & opcode in OPCODE

FINDOPCD LDX #TBL3END-TABLE3-2 ;1ST BYTE OF LAST MODE
NEWOPER CMP $C800
 LDA TABLE3+1,X ;GET BYTE2 OF OPCODE FLAGS
 CMP $CF00
 AND #$FC  ;IGNORE BITS 0 & 1
 CMP OPERAND+1 ;DOES INPUT OPERAND MATCH?
 BNE NEXTOPER ;IF NO
 LDA OPERAND
 AND #$3F  ;IGNORE BITS 6 & 7
 CMP $C800
 CMP TABLE3,X ;DO MODES MATCH?
 STA $CF00
 BNE NEXTOPER ;IF NO

* Operand modes match. Now see if NMEM is available in this mode.

 STX MODE  ;SAVE POSSIBLE (MODE x 2)
 LDX #$0
POSIBLOP JSR TRANSFR3 ;LDA TABLE1,X
 DFB LTABLE1C ;CODE
 CMP OPCODE  ;COMPARE WITH MNEMONIC THAT WAS SAVED HERE
 BEQ CHKMODE
NEXTOPCD INX
 BNE POSIBLOP

* Try next operand from TABLE3

 LDX MODE  ;RESTORE X
NEXTOPER
 DEX
 DEX   ;GOTO NEXT ENTRY IN TABLE 3
 BPL NEWOPER

* Opcode not found

INVPROC SEC   ;SET ERROR CONDITION
 RTS

* Found possible op code, see if modes match

CHKMODE CMP $C800  ;DISABLE EXT RAM
 LDA TABLE2,X ;GET MODE INFO FOR THIS OPCODE
 CMP $CF00  ;ENABLE EXT RAM
 AND #$1F  ;STRIP UNUSED STUFF
 ASL   ;TIMES 2 BECAUSE MODE IS TIMES 2
 CMP MODE  ;DO MODES MATCH, IF SO FOUND OPCODE
 BNE NEXTOPCD ;IF NO

* Found opcode. Is it processor type that is allowed.

 STX OPCODE  ;SAVE
 CMP $C800  ;DISABLE EXT RAM
 LDA TABLE2,X ;GET INFO ON THIS OPCODE
 CMP $CF00  ;ENABLE EXT RAM
 AND #$60  ;STRIP ALL BUT PROCESSOR INFO
 BEQ PROCESOK ;IF 00=6502, MUST BE OK
 BIT CMOSFLAG ;IS 65816 ALLOWED?
 BVS PROCESOK ;IF YES, MUST BE OK
 BPL INVPROC  ;IF 6502 ONLY, THEN INVALID
 CMP #$20  ;IS INSTR 65C02?
 BNE INVPROC  ;IF NO, INVALID

* Opcode is allowed

PROCESOK CLC   ;CLEAR ERROR FLAG
 RTS

*-------------------------------------------------
* Init LOWADD & HIADD with MEMLOW & MEMHI
* Store the contents of the ACC. & verify that it stored
* properely. Returns with Z bit set if verified OK.

INITMMV EQU *
 LDY MEMPBR
 STY DBRDDT ;BANK TO ACCESS
 INDEX16
 LDY MEMLOW
 STY LOWADD
 INDEX8
 PHA
 LDY #0
 JSR TRANSFR3 ;STA LOWADD,Y
 DFB STAINDYC ;CODE
 JSR TRANSFR3 ;LDA LOWADD,Y
 DFB LDAINDYC ;CODE
 STA TEMP
 PLA   ;DID IT STORE PROPERELY?
 CMP TEMP
 RTS

* Increment MEMLOW & MEMHI pointer by 1

INCMEMLH MEMORY16
 INC MEMLOW  ;INC POINTER
 MEMORY8
 RTS

* Load MEMLOW & MEMHI, carry set on error

LOADMEM EQU *
 JSR TRANSFR3 ;CHECK FOR HEX AND READ
 DFB CHKREADC ;CODE
 BCS LOADMRTS ;CARRY SET FOR ERROR
 STA MEMLOW
 LDA LETTER2  ;LOAD POINTER
 STA MEMHI
LOADMRTS
 RTS


***** Pack the mnemonic into 2 bytes *****
*
* MNEMCOMP & MNEMCOMP+1 will contain the compressed mnemonic
* EXAMPLE:  ADC  A= $C1 and with #$1F = %00001
*                D= $C4  "   "     "  = %00100
*                C= $C3  "   "     "  = %00011
*   0 00001 00100 00011 = $0483 compressed form of ADC

PACKMNEM JSR LEFT5
 AND #$1F
 ORA MNEMCOMP+1
 STA MNEMCOMP+1
 RTS

LEFT5 STX XBUFF
 LDX #5
:LEFT ASL MNEMCOMP+1
 ROL MNEMCOMP
 DEX
 BNE :LEFT
 LDX XBUFF
 RTS

* Get the byte pointed to by LOWADD,Y

GETBYTE JSR TRANSFR3 ;GET BYTE FROM PROGRAM RAM
 DFB LDAINDYC ;CODE
 RTS

*----------------------------------------
*  GETCOM3 - do <CR> & get user command

GETCOM3 PEA GETCOMCR-1 ;address of command
 PEA S_GETCOM ;segment of command
 JMP JUMPSEG3 ;goto command

*----------------------------------------
***** THIS SEGMENTS GLOBAL SUBROUTINES *****

SUBTABL3

INITMMVC EQU *-SUBTABL3*4+3+$100
 DA INITMMV-1

DECMEMLHC EQU *-SUBTABL3*4+3+$100
 DA DECMEMLH-1

INCMEMLHC EQU *-SUBTABL3*4+3+$100
 DA INCMEMLH-1

LOADMEMC EQU *-SUBTABL3*4+3+$100
 DA LOADMEM-1

DISASMC EQU *-SUBTABL3*4+3+$100
 DA DISASM-1

*****************************************
*  SEGMENT CROSSOVER AREA  *
*****************************************

 LST ON
S3END = $E0CF91-*
 do nolist
 LST OFF
 fin
 ERR *-1/$E0CF91
 DS $E0CF91-*,$FF

******** SAVE THE ACC, X, Y AND P REGISTERS *******
* Returns with MX = 11, saves registers

SAVEAXP3
 PHP   ;SAVE STATUS
 MX16
 STX XSAVESEG ;save 16 bits
 STY YSAVESEG ;save 16 bits
 STA ASAVESEG ;save 16 bits
 MX8
 PLA   ;GET STATUS
 STA PSAVESEG ;SAVE
 RTS

****** RESTORE THE ACC, X, Y AND P REGISTERS ******
* restores registers

RESTAXP3
 MEMORY8
 LDA PSAVESEG
 PHA
 MX16
 LDX XSAVESEG
 LDY YSAVESEG
 LDA ASAVESEG
 PLP
 RTS
 MX %11

*----------------------------------------
* Do a direct transfer to other segments

JUMPSEG3
 JSR SAVEAXP3
 LDY SLOTN0
 PLA   ;pull junk byte from dest. seg
 PLA   ;get destination segment
 STA SEGMBASE,Y ;the next inst' will be in new seg
 JSR RESTAXP3 ;restore after xfer from other seg
 RTS   ;pull destination address from stack

* TRANSFER TO OTHER SEGMENTS

TRANSFR3

 JSR SAVEAXP3
 MEMORY16
 PLA   ;get return address from stack
 INC   ;inc to point at code byte & for RTS
 PHA
 MEMORY8
 LDA #3  ;CURRENT SEG #
 PHA
 LDY #0
 LDA (2,S),Y  ;GET CODE BYTE
 PHA   ;SAVE CODE
 AND #$07  ;STRIP ALL BUT SEG #
 LDY SLOTN0
 STA SEGMBASE,Y ;NEXT INSTR. RUN FROM NEW SEGMENT
* NEW SEGMENT
 PLA   ;GET CODE
 PEA RETURN3  ;where to return to
 AND #$F8  ;STIP OFF SEG# LEAVING SUB #
 LSR
 LSR   ;LEAVE SUB# MULTIPLIED BY 2
* GET ADDRESS OF SUB FROM SUBTABL & PUSH ON STACK
 TAY
 MEMORY16
 LDA SUBTABL3,Y
 PHA
 BRA RESTAXP3 ;RESTORE REGISTERS, RTS TO SUBROUTINE
 MX %11

* RETURN HERE FROM SUBROUTINE

RETURN3 EQU *-1
 JSR SAVEAXP3
 PLA   ;SEG # TO RETURN TO
 LDY SLOTN0
 STA SEGMBASE,Y ;RETURN TO SEGMENT
 BRA RESTAXP3

 DS \,$FF  ;PUT OBJECT AT NEXT PAGE
